package it.polimi.swKnights.SWIMv2.ejb.friendsEngine;

import it.polimi.swKnights.SWIMv2.ejb.authentication.LoginHandlerLocal;
import it.polimi.swKnights.SWIMv2.ejb.entityBeans.Friendship;
import it.polimi.swKnights.SWIMv2.ejb.entityBeans.FriendshipPk;
import it.polimi.swKnights.SWIMv2.ejb.entityBeans.FriendshipRequest;
import it.polimi.swKnights.SWIMv2.ejb.entityBeans.FriendshipRequestPk;
import it.polimi.swKnights.SWIMv2.ejb.entityBeans.RegisteredUser;
import it.polimi.swKnights.SWIMv2.ejb.exceptions.AlreadyAskedException;
import it.polimi.swKnights.SWIMv2.ejb.exceptions.AlreadyFriendsException;
import it.polimi.swKnights.SWIMv2.ejb.exceptions.InvalidLoginPrivilegesException;
import it.polimi.swKnights.SWIMv2.ejb.exceptions.LoginFailException;
import it.polimi.swKnights.SWIMv2.ejb.exceptions.SelfFriendException;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 * Session Bean implementation class FriendshipRequestManager
 */
@Stateless
public class FriendshipRequestManager implements FriendshipRequestManagerRemote
{
	@PersistenceContext(unitName = "swimv2-manager")
	private EntityManager manager;

	@EJB
	private LoginHandlerLocal loginController;

	@EJB
	private FriendshipManagerLocal friendManager;

	@Override
	public void askFriendship(String friendName, boolean direct,
			String userName, String password) throws LoginFailException,
			InvalidLoginPrivilegesException, SelfFriendException,
			AlreadyAskedException, AlreadyFriendsException
	{
		this.loginController.checkLoginDataAndPrivileges(userName, password,
				RegisteredUser.class);
		this.loginController.checkBanned(userName);

		RegisteredUser user = this.manager.find(RegisteredUser.class, userName);
		RegisteredUser newFriend = this.manager.getReference(
				RegisteredUser.class, friendName);

		if (friendName.equals(userName))
			throw new SelfFriendException();
		if (this.alreadyAsked(userName, friendName))
			throw new AlreadyAskedException();
		if (this.alreadyFriends(userName, friendName))
			throw new AlreadyFriendsException();

		FriendshipRequest nowMyFriend = new FriendshipRequest(user, newFriend,
				direct);
		this.manager.persist(nowMyFriend);
	}

	@Override
	public List<String> getFriendshipRequests(String userName, String password)
			throws LoginFailException, InvalidLoginPrivilegesException
	{
		this.loginController.checkLoginDataAndPrivileges(userName, password,
				RegisteredUser.class);

		List<String> applicantList = new ArrayList<String>();
		RegisteredUser user = this.manager.find(RegisteredUser.class, userName);
		String requestQuery = "select fr.applicant from FriendshipRequest as fr where fr.requested = :user and fr.refused = false";
		Query friendshipRequest = this.manager.createQuery(requestQuery);
		friendshipRequest.setParameter("user", user);
		List<?> results = friendshipRequest.getResultList();
		for (Object item : results)
		{
			RegisteredUser applicantUser = (RegisteredUser) item;
			applicantList.add(applicantUser.getUserName());
		}
		return applicantList;

	}

	@Override
	public void acceptRequest(String applicant, String userName, String password)
			throws EntityNotFoundException, LoginFailException,
			InvalidLoginPrivilegesException
	{
		this.loginController.checkLoginDataAndPrivileges(userName, password,
				RegisteredUser.class);
		this.loginController.checkBanned(userName);

		FriendshipRequest request = this.getFriendshipRequest(applicant,
				userName);
		
		this.cleanFriendshipRequest(userName,applicant);

		this.friendManager.addFriendship(applicant, userName,
				request.isDirect());
		this.manager.remove(request);
	}

	@Override
	public void refuseRequest(String applicant, String userName, String password)
			throws LoginFailException, InvalidLoginPrivilegesException
	{
		this.loginController.checkLoginDataAndPrivileges(userName, password,
				RegisteredUser.class);
		this.loginController.checkBanned(userName);

		FriendshipRequest request = getFriendshipRequest(applicant, userName);
		request.setRefused(true);
		this.manager.persist(request);
	}

	private boolean alreadyAsked(String userName, String friendName)
	{
		FriendshipRequestPk requestId = new FriendshipRequestPk();
		requestId.setRequested(friendName);
		requestId.setApplicant(userName);
	
		return this.manager.find(FriendshipRequest.class, requestId) != null;
	}

	private boolean alreadyFriends(String userName, String friendName)
	{
		Friendship friendship1 = this.findFriendship(userName, friendName);
		Friendship friendship2 = this.findFriendship(friendName, userName);
		
		return friendship1 != null || friendship2 != null;
	}

	private void cleanFriendshipRequest(String userName, String requested)
	{
		FriendshipRequestPk requestId = new FriendshipRequestPk();
		requestId.setRequested(requested);
		requestId.setApplicant(userName);
		
		FriendshipRequest request = this.manager.find(FriendshipRequest.class, requestId);
		
		if(request != null)
		{
			this.manager.remove(request);
		}
		
		
	}

	private Friendship findFriendship(String userName, String friendName)
	{
		FriendshipPk friendshipId = new FriendshipPk();
		friendshipId.setUserName1(friendName);
		friendshipId.setUserName2(userName);
		return this.manager.find(Friendship.class, friendshipId);
	}

	private FriendshipRequest getFriendshipRequest(String applicant,
			String userName)
	{
		FriendshipRequestPk requestId = new FriendshipRequestPk();
		requestId.setRequested(userName);
		requestId.setApplicant(applicant);
		FriendshipRequest request = this.manager.getReference(
				FriendshipRequest.class, requestId);
		return request;
	}

}
